%{
#include<iostream>
#include<cerrno>
#include<string>
#include<sstream>
#include<fstream>
#include "gtree.h"
#include "symtab.h"
#include "check.h"
#define YYSTYPE GTNode*
using namespace std;
int yylex();
extern ofstream irout;
extern stringstream ss,textss;
string get_tag();
string get_label();
void getParams(GTNode* var_list);
void trans_StmtList(GTNode* StmtList);
void release_all();
int has_error=0;
extern int yylineno;
void yyerror(const char* msg){
    cout<<"Error type B at line "<<yylineno<<": "<<msg<<endl;
    has_error=1;
}
%}

%token  INT
%token  FLOAT
%token  ID SEMI COMMA ASSIGNOP RELOP PLUS MINUS STAR DIV AND OR DOT NOT TYPE LP RP LB RB LC RC STRUCT RETURN IF ELSE WHILE

%right ASSIGNOP
%left OR
%left AND
%left RELOP
%left PLUS MINUS
%left STAR DIV
%right NOT 
%left LP RP LB RB DOT
%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE
%error-verbose
%%

Program: ExtDefList {
	$$=newNode(0,"Program",1,$1);
	//if(!has_error)
	// 	travel($$,0);
	}
;
ExtDefList: {$$=newNode(-1,"ExtDefList",0);}
		  | ExtDef ExtDefList {
		  $$=newNode(0,"ExtDefList",2,$1,$2);
            }
		  ;
ExtDef: Specifier ExtDecList SEMI {//全局变量定义
		  $$=newNode(0,"ExtDef",3,$1,$2,$3);
		  global_var_def($$);
	  }
	  | Specifier SEMI {$$=newNode(0,"ExtDef",2,$1,$2);}
	  | Specifier FunDec CompSt {//函数定义
		  $$=newNode(0,"ExtDef",3,$1,$2,$3);
		  textss<<$2->child->name<<":"<<endl;
		  release_all();
		  func_def($$);
          trans_StmtList($3->child->sibiling->sibiling);
          irout << ss.str();
          ss.str("");
	  }
	  | Specifier FunDec SEMI{
	    cout<<"Error type B @"<<$1->lineno<<": Incomplete definition"<<endl;
	  }
	  ;
ExtDecList: VarDec {$$=newNode(0,"ExtDecList",1,$1);}
		  | VarDec COMMA ExtDecList {$$=newNode(0,"ExtDecList",3,$1,$2,$3);}
		  ;
/*Specifier*/ 
Specifier: TYPE {$$=newNode(0,"Specifier",1,$1);}
		 | StructSpecifier {$$=newNode(0,"Specifier",1,$1);}
		 ;
StructSpecifier: STRUCT OptTag LC StructDefList RC {//结构体定义
		$$=newNode(0,"StructSpecifier",5,$1,$2,$3,$4,$5);
		struct_def($$);
	}
			   | STRUCT Tag {//结构体引用
				   $$=newNode(0,"StructSpecifier",2,$1,$2);
			   }
			   ;
OptTag: {$$=newNode(-1,"OptTag",0);}
	  | ID {$$=newNode(0,"OptTag",1,$1);}
	  ;
Tag: ID {$$=newNode(0,"Tag",1,$1);}
;
/*Declarators*/
VarDec: ID {$$=newNode(0,"VarDec",1,$1);}
	  | VarDec LB INT RB {$$=newNode(0,"VarDec",4,$1,$2,$3,$4);}
	  ;
FunDec: ID LP VarList RP {$$=newNode(0,"FunDec",4,$1,$2,$3,$4);getParams($3);}
	  | ID LP RP {$$=newNode(0,"FunDec",3,$1,$2,$3);}

	  ;
VarList: ParamDec COMMA VarList {$$=newNode(0,"VarList",3,$1,$2,$3);}
	   | ParamDec {$$=newNode(0,"VarList",1,$1);}
	   ;
ParamDec: ParamSpecifier VarDec {$$=newNode(0,"ParamDec",2,$1,$2);}
		;
ParamSpecifier: TYPE{$$=newNode(0,"ParamSpecifier",1,$1);}
	|STRUCT Tag{$$=newNode(0,"ParamSpecifier",2,$1,$2);}
/*Statements*/
CompSt: LC DefList StmtList RC {
    $$=newNode(0,"CompSt",4,$1,$2,$3,$4);
}
	;
StmtList: {$$=newNode(-1,"StmtList",0);}
		| Stmt StmtList {
		$$=newNode(0,"StmtList",2,$1,$2);
		}
	    ;
Stmt: Exp SEMI {
    $$=newNode(0,"Stmt",2,$1,$2);
    }
	| CompSt {
	$$=newNode(0,"Stmt",1,$1);
	}
	| RETURN Exp SEMI {$$=newNode(0,"Stmt",3,$1,$2,$3);save_return_type($2);}
	| IF LP Exp RP Stmt %prec LOWER_THAN_ELSE {
	    $$=newNode(0,"Stmt",5,$1,$2,$3,$4,$5);
	}
	| IF LP Exp RP Stmt ELSE Stmt {$$=newNode(0,"Stmt",7,$1,$2,$3,$4,$5,$6,$7);}
	| WHILE LP Exp RP Stmt {$$=newNode(0,"Stmt",5,$1,$2,$3,$4,$5);}
	;
/*Local Definitions*/
DefList: {$$=newNode(-1,"DefList",0);}
	   | Def DefList {$$=newNode(0,"DefList",2,$1,$2);}
	   ;
Def: Specifier DecList SEMI {//局部变量定义
		$$=newNode(0,"Def",3,$1,$2,$3);
		local_var_def($$);
	}
   ;
DecList: Dec {$$=newNode(0,"DecList",1,$1);}
	   | Dec COMMA DecList {$$=newNode(0,"DecList",3,$1,$2,$3);}
	   ;
Dec: VarDec {$$=newNode(0,"Dec",1,$1);}
   | VarDec ASSIGNOP Exp {$$=newNode(0,"Dec",3,$1,$2,$3);}
   ;
   
/*StructDefList*/
StructDefList:{$$=newNode(-1,"StructDefList",0);}
             |StructDef StructDefList{$$=newNode(0,"StructDefList",2,$1,$2);}
StructDef:Specifier StructDecList SEMI{//结构体
    $$=newNode(0,"StructDef",3,$1,$2,$3);
}
StructDecList:VarDec{$$=newNode(0,"StructDecList",1,$1);}
        |VarDec COMMA StructDecList{$$=newNode(0,"StructDecList",3,$1,$2,$3);}
/*Expression*/
Exp: Exp ASSIGNOP Exp {
	$$=newNode(0,"Exp",3,$1,$2,$3);
	assign_op_check($$,$1,$3);
	}
   | Exp AND Exp {
	   $$=newNode(0,"Exp",3,$1,$2,$3);
	   logic_op_check($$,$1,$3);
	   }
   | Exp OR Exp {
	   $$=newNode(0,"Exp",3,$1,$2,$3);
	   logic_op_check($$,$1,$3);
	   }
   | Exp RELOP Exp {
	   $$=newNode(0,"Exp",3,$1,$2,$3);
	   basic_op_check($$,$1,$3);
	   }
   | Exp PLUS Exp {
	   $$=newNode(0,"Exp",3,$1,$2,$3);
	   basic_op_check($$,$1,$3);
	   }
   | Exp MINUS Exp {
	   $$=newNode(0,"Exp",3,$1,$2,$3);
	   basic_op_check($$,$1,$3);
	   }
   | Exp STAR Exp {
	   $$=newNode(0,"Exp",3,$1,$2,$3);
	   basic_op_check($$,$1,$3);
	   }
   | Exp DIV Exp {
	   $$=newNode(0,"Exp",3,$1,$2,$3);
	   basic_op_check($$,$1,$3);
	   }
   | LP Exp RP {$$=newNode(0,"Exp",3,$1,$2,$3);$$->type=$2->type;}
   | MINUS Exp {$$=newNode(0,"Exp",2,$1,$2);$$->type=$2->type;}
   | ID LP Args RP {//函数调用
	   $$=newNode(0,"Exp",4,$1,$2,$3,$4);
	   refer_func_with_param($$);
	   }
   | ID LP RP {//函数调用
	   $$=newNode(0,"Exp",3,$1,$2,$3);
	   refer_func_no_param($$);
    }
   | Exp LB Exp RB {//数组引用
   $$=newNode(0,"Exp",4,$1,$2,$3,$4);
   refer_array($$);
   }
   | Exp DOT ID {//结构体引用
   $$=newNode(0,"Exp",3,$1,$2,$3);
   refer_struct($$);
   }
   | ID {//变量引用
   $$=newNode(0,"Exp",1,$1);
   refer_var($$);
   }
   | INT {
    $$=newNode(0,"Exp",1,$1);$$->type=T_NUM_INT;
   }
   | FLOAT {
   $$=newNode(0,"Exp",1,$1);$$->type=T_NUM_FLOAT;
   }
   ;
Args: Exp COMMA Args {$$=newNode(0,"Args",3,$1,$2,$3);}
	| Exp {$$=newNode(0,"Args",1,$1);}
	;
%%
